package cn.bossfriday.im.protocol.message;

import cn.bossfriday.im.protocol.core.MqttException;
import cn.bossfriday.im.protocol.core.MqttMessage;
import cn.bossfriday.im.protocol.core.MqttMessageHeader;
import cn.bossfriday.im.protocol.enums.ConnectionStatus;
import cn.bossfriday.im.protocol.enums.MqttMessageType;
import cn.bossfriday.im.protocol.enums.QoS;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import java.io.*;

import static cn.bossfriday.im.protocol.core.MqttConstant.FIX_HEADER_LENGTH;

/**
 * ConnAckMessage
 *
 * @author chenx
 */
public class ConnAckMessage extends MqttMessage {

    @Getter
    @Setter
    private int status;

    @Getter
    @Setter
    private String userId;

    @Getter
    @Setter
    private String sessionId;

    @Getter
    @Setter
    private long timestamp;

    public ConnAckMessage() {
        super(MqttMessageType.CONNACK);
    }

    public ConnAckMessage(MqttMessageHeader header) {
        super(header);
    }

    public ConnAckMessage(int status) {
        super(MqttMessageType.CONNACK);
        this.status = status;
    }

    @Override
    protected int getMessageLength() {
        int length = FIX_HEADER_LENGTH;
        if (!StringUtils.isEmpty(this.userId)) {
            length += this.toUtfBytes(this.userId).length;
        }

        if (!StringUtils.isEmpty(this.sessionId)) {
            length += this.toUtfBytes(this.sessionId).length;
        }

        length += Long.BYTES;

        return length;
    }

    @Override
    protected void readMessage(InputStream in, int msgLength) throws IOException {
        // Ignore first byte
        in.read();
        this.status = in.read();
        if (this.status == ConnectionStatus.ACCEPTED.getCode()) {
            DataInputStream dis = new DataInputStream(in);
            this.userId = dis.readUTF();
            this.sessionId = dis.readUTF();
            this.timestamp = dis.readLong();
        }
    }

    @Override
    protected void writeMessage(OutputStream out) throws IOException {
        out.write(0x00);

        int code = this.status;
        if (code < 0 || code > 0xFF) {
            throw new MqttException("Invalid ConnectionStatus code: " + code);
        }

        out.write(code);
        DataOutputStream dos = new DataOutputStream(out);
        if (!StringUtils.isEmpty(this.userId)) {
            dos.writeUTF(this.userId);
        }

        if (!StringUtils.isEmpty(this.sessionId)) {
            dos.writeUTF(this.sessionId);
        }

        dos.writeLong(this.timestamp);
        dos.flush();
    }


    @Override
    public void setDup(boolean dup) {
        throw new MqttException("ConnAckMessage don't use the DUP flag.");
    }

    @Override
    public void setRetained(boolean retain) {
        throw new MqttException("ConnAckMessage don't use the RETAIN flag.");
    }

    @Override
    public void setQos(QoS qos) {
        throw new MqttException("ConnAckMessage don't use the QoS flags.");
    }
}
